package com.chipcoo.web.servlet.view;

import com.chipcoo.web.utils.MediaTypeUtils;
import com.chipcoo.web.utils.ViewUtils;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.SmartView;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public class ContentNegotiatingViewResolver extends org.springframework.web.servlet.view.ContentNegotiatingViewResolver {

    @Override
    public View resolveViewName(String viewName, Locale locale) throws Exception {
        RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
        Assert.isInstanceOf(ServletRequestAttributes.class, attrs);
        HttpServletRequest httpServletRequest = ((ServletRequestAttributes) attrs).getRequest();
        List<MediaType> requestedMediaTypes = MediaTypeUtils.getRequestSupportedMediaTypes(httpServletRequest,MediaTypeUtils.getAcceptableMediaTypes(httpServletRequest,super.getContentNegotiationManager()));
        /*if(null!= httpServletRequest.getAttribute(MediaTypeUtils.HTTP_SERVLET_REQUEST_MEDIA_TYPES))
            requestedMediaTypes = (List<MediaType>)httpServletRequest.getAttribute(MediaTypeUtils.HTTP_SERVLET_REQUEST_MEDIA_TYPES);
        else
            requestedMediaTypes = getMediaTypes(httpServletRequest);*/

        if (requestedMediaTypes != null) {
            List<View> candidateViews = getCandidateViews(viewName, locale, requestedMediaTypes);

            View bestView = getBestView(candidateViews, requestedMediaTypes, attrs);

            if (bestView != null) {

                return bestView;
            }
        }

        if (super.isUseNotAcceptableStatusCode()) {
            if (logger.isDebugEnabled()) {
                logger.debug("No acceptable view found; returning 406 (Not Acceptable) status code");
            }
            return ViewUtils.NOT_ACCEPTABLE_VIEW;
        }else {
            logger.debug("No acceptable view found; returning null");
            return null;
        }
    }
    private List<View> getCandidateViews(String viewName, Locale locale, List<MediaType> requestedMediaTypes)
            throws Exception {
        List<View> candidateViews = new ArrayList<View>();

        for (ViewResolver viewResolver : super.getViewResolvers()) {
            View view = viewResolver.resolveViewName(viewName, locale);
            if (view != null) {
                candidateViews.add(view);
            }
        }

        if (!CollectionUtils.isEmpty(this.getDefaultViews())) {

            candidateViews.addAll(this.getDefaultViews());
        }
        return candidateViews;
    }
    private View getBestView(List<View> candidateViews, List<MediaType> requestedMediaTypes, RequestAttributes attrs) {
        for (View candidateView : candidateViews) {
            if (candidateView instanceof SmartView) {
                SmartView smartView = (SmartView) candidateView;
                if (smartView.isRedirectView()) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Returning redirect view [" + candidateView + "]");
                    }
                    return candidateView;
                }
            }
        }
        for (MediaType mediaType : requestedMediaTypes) {
            for (View candidateView : candidateViews) {
                if (StringUtils.hasText(candidateView.getContentType())) {
                    MediaType candidateContentType = MediaType.parseMediaType(candidateView.getContentType());
                    if (mediaType.isCompatibleWith(candidateContentType)) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("Returning [" + candidateView + "] based on requested media type '" +
                                    mediaType + "'");
                        }
                        attrs.setAttribute(View.SELECTED_CONTENT_TYPE, mediaType, RequestAttributes.SCOPE_REQUEST);
                        return candidateView;
                    }
                }
            }
        }
        return null;
    }


}
